package com.hwbsite.hwbback.service;

import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import cn.hutool.jwt.JWTUtil;
import com.hwbsite.hwbback.consstants.CacheConstants;
import com.hwbsite.hwbback.consstants.CommonConstants;
import com.hwbsite.hwbback.entity.HwbUser;
import com.hwbsite.hwbback.entity.UserDTO;
import com.hwbsite.hwbback.entity.UserInfo;
import com.hwbsite.hwbback.utils.TokenRes;
import jakarta.servlet.http.HttpServletResponse;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Service;

import java.util.Collections;
import java.util.HashMap;
import java.util.concurrent.TimeUnit;

@Service
@Slf4j
@AllArgsConstructor
public class AuthService {
    private final AuthenticationManager authenticationManager;
    private final RedisTemplate redisTemplate15;
    private final CommonService commonService;
    private final UserService userService;


    public TokenRes token(UserDTO dto, HttpServletResponse response) {
        String type = dto.getGrantType();
        if("password".equals(type)){
          return this.login(dto, response);
        }
        if("refresh_token".equals(type)){
            return this.refreshToken(dto, response);
        }
        return TokenRes.builder().build();
    }

    private TokenRes login(UserDTO dto, HttpServletResponse response){

        if(StrUtil.isBlank(dto.getUsername()) || StrUtil.isBlank(dto.getPassword())){
            return TokenRes.builder().build();
        }
        Authentication authentication;
        try{
            authentication = authenticationManager.authenticate(
                    new UsernamePasswordAuthenticationToken(
                            dto.getUsername(),
//                            new BCryptPasswordEncoder().encode(dto.getPassword())
                            dto.getPassword()
                    )
            );
        }catch (Exception e){
            redisTemplate15.delete(CacheConstants.USER_DETAILS + dto.getUsername());
            log.error(e.getMessage(),e);
            response.setStatus(400);
            return TokenRes.builder().error_description(e.getMessage()).build();
        }

        // 用户信息
        HwbUser user = (HwbUser) authentication.getPrincipal();

        if(redisTemplate15.hasKey(CacheConstants.USER_TOKEN_ED + user.getUserId())){
          String tokens =  (String) redisTemplate15.opsForValue().get(CacheConstants.USER_TOKEN_ED + user.getUserId());

          return JSONUtil.toBean(tokens, TokenRes.class);
        }

        String token = JWTUtil.createToken(JSONUtil.toBean(JSONUtil.toJsonStr(user), HashMap.class), CommonConstants.JWT_KEY.getBytes());
        String refresh = JWTUtil.createToken(JSONUtil.toBean(JSONUtil.toJsonStr(user), HashMap.class), CommonConstants.JWT_KEY.getBytes());

        TokenRes res = TokenRes.builder().access_token(token).refresh_token(refresh).build();

        redisTemplate15.opsForValue()
                .set(CacheConstants.USER_TOKEN_ED + user.getUserId(), JSONUtil.toJsonStr(res), 604800, TimeUnit.SECONDS  );
        redisTemplate15.opsForValue()
                .set(CacheConstants.USER_TOKEN + token, user.getUserId(),  604800, TimeUnit.SECONDS  );
        redisTemplate15.opsForValue()
                .set(CacheConstants.RE_USER_TOKEN + refresh, user.getUserId(), 2419200, TimeUnit.SECONDS  );


        return res;


    }


    private TokenRes refreshToken(UserDTO dto ,HttpServletResponse response){
        if(StrUtil.isBlank( dto.getRefreshToken())){
            return TokenRes.builder().build();
        }
        if(!redisTemplate15.hasKey(CacheConstants.RE_USER_TOKEN + dto.getRefreshToken())){
            response.setStatus(405);
            return TokenRes.builder().build();
        }

        String userId = (String) JWTUtil.parseToken(dto.getRefreshToken()).getPayload("userId");
        UserInfo user = userService.getUserById(userId);
        commonService.logOut(user);

        String token = JWTUtil.createToken(JSONUtil.toBean(JSONUtil.toJsonStr(user), HashMap.class), CommonConstants.JWT_KEY.getBytes());
        String refresh = JWTUtil.createToken(JSONUtil.toBean(JSONUtil.toJsonStr(user), HashMap.class), CommonConstants.JWT_KEY.getBytes());

        TokenRes res = TokenRes.builder().access_token(token).refresh_token(refresh).build();

        redisTemplate15.opsForValue()
                .set(CacheConstants.USER_TOKEN_ED + user.getUserId(), JSONUtil.toJsonStr(res), 604800, TimeUnit.SECONDS  );
        redisTemplate15.opsForValue()
                .set(CacheConstants.USER_TOKEN + token, user.getUserId(),  604800, TimeUnit.SECONDS  );
        redisTemplate15.opsForValue()
                .set(CacheConstants.RE_USER_TOKEN + refresh, user.getUserId(), 2419200, TimeUnit.SECONDS  );

        return res;
    }
}
